#include <stdio.h>
#include <string.h>

#include "casl.h"

#include "os.h"

#include "memory.h"

static WORD *memory = NULL;
static unsigned char memoryModified[MEMORY_SIZE / WORD_PER_LINE / (sizeof (char) * 8)];

/* set modified of address
 *
 * input:
 *   address - the address is to set
 */
static void
SetModified (UWORD address)
{
  memoryModified[address / WORD_PER_LINE / (sizeof (char) * 8)] |=
    1 << address / WORD_PER_LINE % (sizeof (char) * 8);
}

/* get modified of address
 *
 * input:
 *   address - the address~address+7 8 WORDs is to get
 * output:
 *   return - TRUE if modified, or FALSE if address~address+7 8 WORDs all no modified
 */
int
GetModified (UWORD address)
{
  if (memoryModified[address / WORD_PER_LINE / (sizeof (char) * 8)]!= 0)
    return TRUE;
  else
    return FALSE;
}

/* clear memoryModified[] to zero
 *
 * input:
 *   address - the address~address+7 8 WORDs is to set zero
 */
void ClearModified(UWORD address)
{
  memoryModified[address / WORD_PER_LINE / (sizeof (char) * 8)]=0;
}

void
CodeRead (UWORD address, CODE * code)
{
  memcpy (code, memory + address, sizeof (CODE));
}

void
CodeWrite (UWORD address, CODE * code)
{
  memcpy (memory + address, code, sizeof (CODE));
  SetModified (address);
  SetModified (address + 1);
}

int
memoryWrite (UWORD address, WORD value)
{
  memory[address] = value;
  SetModified (address);

  return TRUE;			/* succeed in writing */
}

WORD
memoryRead (UWORD address)
{
  return memory[address];
}

void
memoryClear (void)
{
  UWORD address;

  if (memory != NULL)
    memset (memory, 0, end_PC);

  for (address = 0; address < end_PC; address++)
    SetModified (address);
}

/* memory alloc
 *
 * return TRUE, if suceed
 *        FALSE, if fail
 */
int
memoryInit (void)
{
  if ((memory = (WORD *) malloc (MEMORY_SIZE * sizeof (WORD))) == NULL)
    {
      display (_("No enough memory!\n"));
      return FALSE;
    }
  else
    return TRUE;
}

void
memoryFree (void)
{
  if (memory)
    free (memory);
}
